{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://course.rs/basic/lifetime.html\n",
    "- https://practice-zh.course.rs/lifetime/basic.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/lifetime/basic.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生命周期，简而言之就是引用的有效作用域"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 悬垂指针和生命周期\n",
    "\n",
    "生命周期的主要作用是避免悬垂引用，它会导致程序引用了本不该引用的数据：\n",
    "- 在这里 `r` 拥有更大的作用域，或者说**活得更久**。如果 Rust 不阻止该悬垂引用的发生，那么当 `x` 被释放后，`r` 所引用的值就不再是合法的，会导致我们程序发生异常行为，且该异常行为有时候会很难被发现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`x` does not live long enough",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0597] Error:\u001b[0m `x` does not live long enough",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_8:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;68m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m binding `x` declared here",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m borrowed value does not live long enough",
      " \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m}\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m `x` dropped here while still borrowed",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m9 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;37mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;37m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m borrow later used here",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let r;\n",
    "\n",
    "    {\n",
    "        let x = 5;\n",
    "        r = &x;\n",
    "    }\n",
    "\n",
    "    println!(\"r: {}\", r);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `let r;`的声明方式貌似存在使用 null 的风险，实际上，当我们不初始化它就使用时，编译器会给予报错\n",
    "- `r = &x;`: r 引用了内部花括号中的 `x` 变量，但是 `x` 会在内部花括号 `}` 处被释放，因此回到外部花括号后，`r` 会引用一个无效的 `x;`, `r` 就是一个悬垂指针，它引用了提前被释放的变量 `x`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 借用检查\n",
    "\n",
    "为了保证 Rust 的所有权和借用的正确性，Rust 使用了一个借用检查器(Borrow checker)，来检查我们程序的借用正确性："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`x` does not live long enough",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0597] Error:\u001b[0m `x` does not live long enough",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m+\u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;68m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m binding `x` declared here",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m borrowed value does not live long enough",
      " \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m}\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m+\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m `x` dropped here while still borrowed",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m9 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;37mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;37m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m borrow later used here",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let r;                // ---------+-- 'a\n",
    "                          //          |\n",
    "    {                     //          |\n",
    "        let x = 5;        // -+-- 'b  |\n",
    "        r = &x;           //  |       |\n",
    "    }                     // -+       |\n",
    "                          //          |\n",
    "    println!(\"r: {}\", r); //          |\n",
    "}                         // ---------+"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "r: 5\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let x = 5;            // ----------+-- 'b\n",
    "                          //           |\n",
    "    let r = &x;           // --+-- 'a  |\n",
    "                          //   |       |\n",
    "    println!(\"r: {}\", r); //   |       |\n",
    "                          // --+       |\n",
    "}                         // ----------+"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 函数中的生命周期\n",
    "\n",
    "在存在多个引用时，编译器有时会无法自动推导生命周期，此时就需要我们手动去标注，通过为参数标注合适的生命周期来帮助编译器进行借用检查的分析。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "missing lifetime specifier",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0106] Error:\u001b[0m missing lifetime specifier",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_14:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m9 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                                 \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                 \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected named lifetime parameter",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let string1 = String::from(\"abcd\");\n",
    "    let string2 = \"xyz\";\n",
    "\n",
    "    let result = longest(string1.as_str(), string2);\n",
    "    println!(\"The longest string is {}\", result);\n",
    "}\n",
    "\n",
    "fn longest(x: &str, y: &str) -> &str {\n",
    "    if x.len() > y.len() {\n",
    "        x\n",
    "    } else {\n",
    "        y\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 生命周期标注语法\n",
    "\n",
    "- **标注只是说明关系**：生命周期标注不会延长引用的真实存活时间，它只是告诉编译器“这些引用之间至少要活得一样久”。\n",
    "- **语法形式**：生命周期名字以 `'` 开头，常用 `'a`。标注写在 `&` 后：`&'a T`、`&'a mut T`。\n",
    "- **作用**：帮助借用检查器判断多个引用的相对生存期，从而避免悬垂引用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn longest<'a>(x: &'a str, y: &'a str) -> &'a str"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**函数签名中的生命周期**\n",
    "- 先声明 `<'a>`，再在参数与返回值上使用。\n",
    "- 这里表示：返回值需要活得和 `x`、`y` 中较短的那个生命周期一样久。\n",
    "- 编译器据此判断：如果参数有短命者，返回值也不能超出它的作用域。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "missing lifetime specifier",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0106] Error:\u001b[0m missing lifetime specifier",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_15:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m9 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                                 \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                 \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected named lifetime parameter",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let string1 = String::from(\"abcd\");\n",
    "    let string2 = \"xyz\";\n",
    "\n",
    "    let result = longest(string1.as_str(), string2);\n",
    "    println!(\"The longest string is {}\", result);\n",
    "}\n",
    "\n",
    "fn longest(x: &str, y: &str) -> &str {\n",
    "    if x.len() > y.len() {\n",
    "        x\n",
    "    } else {\n",
    "        y\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 当 `string2` 比 `string1` 早结束作用域时，`longest` 的返回值被迫短命；若仍在外层使用，就会触发 `E0597`。\n",
    "- 如果函数返回内部临时变量的引用，生命周期无法满足要求，会报 `E0515`。解决方法：返回所有权（例如直接返回 `String`）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The longest string is abcd\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let string1 = String::from(\"abcd\");\n",
    "    let string2 = \"xyz\";\n",
    "\n",
    "    let result = longest(string1.as_str(), string2);\n",
    "    println!(\"The longest string is {}\", result);\n",
    "}\n",
    "\n",
    "fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {\n",
    "    if x.len() > y.len() {\n",
    "        x\n",
    "    } else {\n",
    "        y\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 未使用某个参数时，不必为它标注生命周期。\n",
    "- 函数返回引用时，生命周期要么来自参数，要么来自函数内部数据；后者会导致悬垂引用，必须避免。\n",
    "- 生命周期标注的目标，是让编译器理解引用之间的生存关系，从而在编译期保障内存安全。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 结构体中的生命周期\n",
    "\n",
    "结构体中包含引用字段时必须显式标注生命周期，以确保被引用的数据在结构体实例存活期间始终有效，否则会因悬垂引用而导致编译错误。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "struct ImportantExcerpt<'a> {\n",
    "    part: &'a str,\n",
    "}\n",
    "\n",
    "{\n",
    "    let novel = String::from(\"Call me Ishmael. Some years ago...\");\n",
    "    let first_sentence = novel.split('.').next().expect(\"Could not find a '.'\");\n",
    "    let i = ImportantExcerpt {\n",
    "        part: first_sentence,\n",
    "    };\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`novel` does not live long enough",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0597] Error:\u001b[0m `novel` does not live long enough",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_19:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m 9 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mo\u001b[0m\u001b[38;5;68mv\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68ml\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mC\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mI\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m             \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m               \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m binding `novel` declared here",
      " \u001b[38;5;246m10 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mC\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                              \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m borrowed value does not live long enough",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;246m14 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m}\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m     \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m     \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m `novel` dropped here while still borrowed",
      " \u001b[38;5;246m15 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m?\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;37mi\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                     \u001b[38;5;37m┬\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                     \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m borrow later used here",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "#[derive(Debug)]\n",
    "struct ImportantExcerpt<'a> {\n",
    "    part: &'a str,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let i;\n",
    "    {\n",
    "        let novel = String::from(\"Call me Ishmael. Some years ago...\");\n",
    "        let first_sentence = novel.split('.').next().expect(\"Could not find a '.'\");\n",
    "        i = ImportantExcerpt { // 结构体比它引用的字符串活得更久\n",
    "            part: first_sentence,\n",
    "        };\n",
    "    }\n",
    "    println!(\"{:?}\",i);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 生命周期消除\n",
    "\n",
    "**背景**：所有引用都拥有生命周期，但手写代码时常不必显式标注，是因为编译器应用了“生命周期消除规则”自动推断。\n",
    "\n",
    "**问题来源**：函数返回引用时，若引用来自参数，就能安全返回，否则会造成悬垂引用。\n",
    "\n",
    "三条消除规则\n",
    "- **规则一**：每个引用类型的参数各自获得独立的生命周期标注（输入生命周期）。\n",
    "- **规则二**：若函数只有一个引用参数，则该参数的生命周期自动赋给所有返回引用（输出生命周期）。\n",
    "- **规则三**：若函数有多个引用参数且其中含 `&self` 或 `&mut self`，则返回引用默认沿用 `self` 的生命周期（方法专用）。\n",
    "\n",
    "**规则的限制**：当规则无法唯一确定返回引用来源时（如多个参数且无 `&self`），编译器会报错，需要手动标注生命周期。\n",
    "\n",
    "**实践意义**：这些规则大幅减少了日常开发中的生命周期标注负担；当默认推断不匹配需求时，再显式标注即可。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**例子 1**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn first_word(s: &str) -> &str { // 实际项目中的手写代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 首先，我们手写的代码如上所示时，编译器会先应用第一条规则，为每个参数标注一个生命周期：\n",
    "fn first_word<'a>(s: &'a str) -> &str { // 编译器自动为参数添加生命周期"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 此时，第二条规则就可以进行应用，因为函数只有一个输入生命周期，因此该生命周期会被赋予所有的输出生命周期：\n",
    "fn first_word<'a>(s: &'a str) -> &'a str { // 编译器自动为返回值添加生命周期"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "source": [
    "此时，编译器为函数签名中的所有引用都自动添加了具体的生命周期，因此编译通过，且用户无需手动去标注生命周期，只要按照 `fn first_word(s: &str) -> &str { `的形式写代码即可。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "source": [
    "**例子 2**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn longest(x: &str, y: &str) -> &str { // 实际项目中的手写代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 首先，编译器会应用第一条规则，为每个参数都标注生命周期：\n",
    "fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "missing lifetime specifier",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0106] Error:\u001b[0m missing lifetime specifier",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_20:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                                     \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                     \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected named lifetime parameter",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// https://godbolt.org/z/jc4EorM9o 给了如何修改的提示\n",
    "\n",
    "{\n",
    "    fn longest(x: &str, y: &str) -> &str {\n",
    "        if x.len() >= y.len() {\n",
    "            x\n",
    "        } else {\n",
    "            y\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "Shell command failed with exit code 101: error[E0106]: missing lifetime specifier\n --> src/main.rs:1:33\n  |\n1 | fn longest(x: &str, y: &str) -> &str {\n  |               ----     ----     ^ expected named lifetime parameter\n  |\n  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`\nhelp: consider introducing a named lifetime parameter\n  |\n1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {\n  |           ++++     ++          ++          ++\n\nFor more information about this error, try `rustc --explain E0106`.\nerror: could not compile `lifetime` (bin \"lifetime\") due to 1 previous error\n",
     "output_type": "error",
     "traceback": [
      "Shell command failed with exit code 101: error[E0106]: missing lifetime specifier\n --> src/main.rs:1:33\n  |\n1 | fn longest(x: &str, y: &str) -> &str {\n  |               ----     ----     ^ expected named lifetime parameter\n  |\n  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`\nhelp: consider introducing a named lifetime parameter\n  |\n1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {\n  |           ++++     ++          ++          ++\n\nFor more information about this error, try `rustc --explain E0106`.\nerror: could not compile `lifetime` (bin \"lifetime\") due to 1 previous error\n"
     ]
    }
   ],
   "source": [
    "! cd lifetime && cargo run -q"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是此时，第二条规则却无法被使用，因为输入生命周期有两个，第三条规则也不符合，因为它是函数，不是方法，因此没有 `&self` 参数。在套用所有规则后，编译器依然无法为返回值标注合适的生命周期，因此，编译器就会报错，提示我们需要手动标注生命周期："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The longest string is long string is long\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {\n",
    "    if x.len() >= y.len() {\n",
    "        x\n",
    "    } else {\n",
    "        y\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let string1 = String::from(\"long string is long\");\n",
    "    let string2 = \"xyz\";\n",
    "\n",
    "    let result = longest(string1.as_str(), string2);\n",
    "    println!(\"The longest string is {}\", result);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 方法中的生命周期\n",
    "\n",
    "- **生命周期同样属于类型声明的一部分**：为带引用字段的结构体实现方法时，`impl` 块必须包含生命周期参数（如 `impl<'a> ImportantExcerpt<'a>`），因为生命周期标注是结构体类型的一部分。\n",
    "- **方法签名通常无需手写生命周期**：借助生命周期消除规则中的第一条（为每个输入引用推断生命周期）和第三条（若存在 `&self`/`&mut self`，返回值默认继承其生命周期），大多数方法的参数与返回值都能自动推断生命周期。\n",
    "- **多输入引用时的推断过程**：\n",
    "  1. 编译器先为每个输入引用生成独立的生命周期参数，例如 `&'a self`、`&'b str`。\n",
    "  2. 若方法返回引用且含 `&self`，第三条规则会把 `&self` 的生命周期赋给返回值，从而消除生命周期标注的需求。\n",
    "- **手动标注的场景**：当你希望返回值的生命周期不同于 `&self` 时，需显式标注并描述生命周期之间的关系，否则编译器无法推断。例如：\n",
    "  - 直接使用 `'a` 返回值：`fn announce_and_return_part<'b>(&'a self, announcement: &'b str) -> &'a str`.\n",
    "  - 若返回值想使用 `'b`，必须声明 `'a: 'b` 这样的生命周期约束，说明 `'a` 至少和 `'b` 一样长（`'a` “包住” `'b`），才能确保引用安全。\n",
    "- **生命周期约束语法**：`'a: 'b` 与泛型约束类似，表示 `'a` 存活时间不短于 `'b`。可以在 `impl` 头部或 `where` 子句中声明。\n",
    "\n",
    "> 总之：在方法中，生命周期的书写和泛型参数非常类似。默认依靠生命周期消除规则即可应付大多数情况；一旦返回值的生命周期关系与默认推断不同，就显式添加生命周期和必要的约束，让编译器确信引用始终有效。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 泛型的语法\n",
    "\n",
    "struct Point<T> {\n",
    "    x: T,\n",
    "    y: T,\n",
    "}\n",
    "\n",
    "impl<T> Point<T> {\n",
    "    fn x(&self) -> &T {\n",
    "        &self.x\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 为具有生命周期的结构体实现方法\n",
    "\n",
    "struct ImportantExcerpt<'a> {\n",
    "    part: &'a str,\n",
    "}\n",
    "\n",
    "impl<'a> ImportantExcerpt<'a> {\n",
    "    fn level(&self) -> i32 {\n",
    "        3\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "struct ImportantExcerpt<'a> {\n",
    "    part: &'a str,\n",
    "}\n",
    "\n",
    "impl<'a> ImportantExcerpt<'a> {\n",
    "    fn part(&self) -> &str { // 方法 part 既没显式写生命周期，也能返回 &str，因为编译器根据规则自动推断出返回值借用自 &self\n",
    "        self.part\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let text = String::from(\"Fear cuts deeper than swords.\");\n",
    "    let excerpt = ImportantExcerpt { part: &text[0..4] };\n",
    "\n",
    "    println!(\"{}\", excerpt.part());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "显示“生命周期消除规则无法推断 → 编译报错 → 手动补充生命周期后通过”的全过程"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "lifetime may not live long enough",
     "output_type": "error",
     "traceback": [
      "\u001b[31mError:\u001b[0m lifetime may not live long enough",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_24:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;100m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;100m┬\u001b[0m                    \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m let's call the lifetime of this reference `'2`",
      " \u001b[38;5;240m  │\u001b[0m                                  \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                  \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m let's call the lifetime of this reference `'1`",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m9 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68ma\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mo\u001b[0m\u001b[38;5;68mu\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mc\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mm\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mt\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "struct ImportantExcerpt<'a> {\n",
    "    part: &'a str,\n",
    "}\n",
    "\n",
    "impl<'a> ImportantExcerpt<'a> {\n",
    "    fn echo(&self, announcement: &str) -> &str {\n",
    "        println!(\"Attention please: {}\", announcement);\n",
    "        announcement\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 生命周期消除规则 1 和 3 生效后，方法签名会被推断为：`fn echo<'a, 'b>(&'a self, announcement: &'b str) -> &'a str`\n",
    "- 返回值被默认赋予 `&self`（即 `'a`）的生命周期。\n",
    "- 但函数体实际返回的是 `announcement`，它的生命周期是 `'b`。编译器无法确认 'b 至少和 `'a` 一样长，因此拒绝编译。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Attention please: Winter is coming!\n",
      "Winter is coming!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 手动补充生命周期的修正版\n",
    "\n",
    "struct ImportantExcerpt<'a> {\n",
    "    part: &'a str,\n",
    "}\n",
    "\n",
    "// - 显式声明新的生命周期参数 'b，专门描述 announcement。\n",
    "// - 返回类型改为 &'b str，让编译器知道返回值与 announcement 同寿命，而不再强制继承 &self 的生命周期。\n",
    "impl<'a> ImportantExcerpt<'a> {\n",
    "    fn echo<'b>(&'a self, announcement: &'b str) -> &'b str {\n",
    "        println!(\"Attention please: {}\", announcement);\n",
    "        announcement\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let text = String::from(\"Fear cuts deeper than swords.\");\n",
    "    let excerpt = ImportantExcerpt { part: &text[..] };\n",
    "\n",
    "    let shout = String::from(\"Winter is coming!\");\n",
    "    let echoed = excerpt.echo(&shout);\n",
    "    println!(\"{}\", echoed);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "impl<'a: 'b, 'b> ImportantExcerpt<'a> {\n",
    "    fn method1(&'a self, arg: &'b str) -> &'b str { /* ... */ }\n",
    "    fn method2(&'a self, arg: &'b str) -> &'b str { /* ... */ }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "约束写在 `impl` 的泛型参数列表里 → 作用于整个 `impl` 块\n",
    "- 这里的 `'a: 'b` 在 `impl` 头部声明。\n",
    "- 整个 `impl` 块里的所有方法都会自动继承 `‘a: ’b` 这个约束。\n",
    "- 换句话说，无论你在这个 `impl` 里写多少个方法，它们都必须满足 `'a` 至少和 `'b` 一样长。\n",
    "- 适合“该 `impl` 中的所有方法都需要这一关系”的场景。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "impl<'a> ImportantExcerpt<'a> {\n",
    "    fn method1<'b>(&'a self, arg: &'b str) -> &'b str\n",
    "    where\n",
    "        'a: 'b,\n",
    "    {\n",
    "        /* ... */\n",
    "    }\n",
    "\n",
    "    fn method2(&'a self) -> i32 {\n",
    "        42\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "约束写在某个方法的签名（或 `where` 子句）里 → 仅作用于该方法\n",
    "- 这里的 `impl` 只声明 `'a`。\n",
    "- `'b` 只在 `method1` 中出现，并通过 `where 'a: 'b` 表示“对 `method1` 而言，`'a` 至少和 `'b` 一样长”。\n",
    "- `method2` 没有 `'b`，也不需要 `'a: 'b` 约束，不会受到影响。\n",
    "- 适合“只有少数方法需要额外约束，其它方法不需要”的场景，更加灵活。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 静态生命周期\n",
    "\n",
    "- `'static` 表示引用可与整个程序同生共死，是最长久的生命周期。\n",
    "- 字符串字面量等被硬编码进二进制的值天然拥有 `&'static str`。\n",
    "- 面对生命周期报错，先排查是否存在悬垂引用或生命周期不匹配的问题；不要一上来就套 `T: 'static`。\n",
    "- 当确知数据确实能存活足够久，而编译器难以推断时，可以合理使用 `'static`（如 `&'static` 或泛型约束 `T: 'static`）。\n",
    "- `'static` 有两种常见写法：直接的 `&'static` 引用，以及表示类型中所有引用都必须为 `'static` 的约束 `T: 'static`。\n",
    "\n",
    "> 事实上，关于 `'static`, 有两种用法: `&'static` 和 `T: 'static`，详细内容请参见[此处](https://course.rs/advance/lifetime/static.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 一个复杂例子: 泛型、特征约束"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::fmt::Display;\n",
    "\n",
    "fn longest_with_an_announcement<'a, T>(\n",
    "    x: &'a str,\n",
    "    y: &'a str,\n",
    "    ann: T,\n",
    ") -> &'a str\n",
    "where\n",
    "    T: Display,\n",
    "{\n",
    "    println!(\"Announcement! {}\", ann);\n",
    "    if x.len() > y.len() {\n",
    "        x\n",
    "    } else {\n",
    "        y\n",
    "    }\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "Rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
